#include "uart.c"

// 按键状态
typedef enum
{
    IDEL,          // 按键空闲状态
    PRESSED,       // 按键被按下
    RELEASED,      // 按键释放，作为按键次数的计数
    RELEASED_WAIT, // 做按键等待超时
    LONG_PRESS     // 长按
} KeyState;

#define LONG_PRESS_TIME_MS 1000
#define RELEASED_TIMEOUT_MS 500

void delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < 123; j++)
            ;
    }
}

sbit BTN = P3 ^ 5;

void main()
{
    // BTN的值， state 当前的值
    KeyState state = IDEL;
    // 长按的时间判断，当变量累加到一个阈值，则认为是长按
    unsigned int pressed_time_counter = 0;
    // 连续点击按键，中间的时间间隔是一个比较短的时间间隔
    // 如果超过这个短的时间间隔，就和之前的按键做分割
    // 当出现超过阈值时间的时候，认为是一个阶段，进行LED灯展示
    unsigned int released_time_counter = 0;
    // 按键次数，用来确定是单击、双击、三击，
    // 当release_time_counter在一个较短时间内再次按键，这个变量+1
    unsigned int pressed_count = 0;

    uart_init();

    while (1)
    {
        switch (state)
        {
        case IDEL:
            //  程序一开始，或者按键抬起超过一段时间后，进入IDEL状态
            if (BTN == 0)
            {
                state = PRESSED;
            }
            break;
        case PRESSED:
            // 当IDEL、RELEASE、RELEASE_WAIT 中 按键按下时，进入此状态
            if (BTN == 0)
            {
                // 判断是否进入长按状态
                if (pressed_time_counter >= LONG_PRESS_TIME_MS)
                {
                    state = LONG_PRESS;
                    pressed_time_counter = 0;
                }
                else
                {
                    pressed_time_counter++;
                    // 延时一个大概的时间
                    // 使得达到阈值的时间接近真实时间
                    delay_ms(1);
                }
            }
            else
            {
                state = RELEASED;
                pressed_time_counter = 0;
            }
            break;
        case RELEASED:
            // 当PRESSED、RELEASE_WAIT 中按键抬起，进入此状态
            // 状态的目的：为了进行按键计数
            delay_ms(10); // 去处抖动
            if (BTN == 1)
            {
                // 进行按键计数，确保此状态只会被循环执行一次
                pressed_count++;
                printf("%d\n", (int)(pressed_count));
                state = RELEASED_WAIT;
            }
            else
            {
                state = PRESSED;
            }
            break;
        case RELEASED_WAIT:
            // 状态目的：记录按键抬起后的时间，超过时间进行灯的展示
            // 做按键抬起的计数，进行按键时长的切割
            // 当按键长时间抬起，状态进入到IDEL
            if (BTN == 0)
            {
                state = PRESSED;
            }
            else
            {
                if (released_time_counter >= RELEASED_TIMEOUT_MS)
                {
                    // 按键被完全释放，根据按下的次数，点亮LED
                    if (pressed_count >= 3)
                    {
                        P2 = ~0x07;
                    }
                    else if (pressed_count == 2)
                    {
                        P2 = ~0x03;
                    }
                    else if (pressed_count == 1)
                    {
                        P2 = ~0x01;
                    }
                    state = IDEL;
                    pressed_count = 0;
                    released_time_counter = 0;
                    printf("reset:%d\n", (int)pressed_count);
                }
                else
                {
                    released_time_counter++;
                    delay_ms(1);
                }
            }
            break;
        case LONG_PRESS:
            // 进入长按状态，如果按键持续按下，则LED展示状态
            // 按键抬起，重置状态。
            if (BTN == 1)
            {
                state = IDEL;
                pressed_count = 0;
                P2 = 0xFF;
            }
            else
            {
                P2 = 0xF0;
            }
            break;
        default:
            break;
        }
    }
}